package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.mapper.AlbumAttributeValueMapper;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.common.config.pool.ThreadPoolConfig;
import com.atguigu.tingshu.common.constant.RabbitConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.search.AttributeValueIndex;
import com.atguigu.tingshu.query.album.AlbumInfoQuery;
import com.atguigu.tingshu.vo.album.AlbumAttributeValueVo;
import com.atguigu.tingshu.vo.album.AlbumInfoVo;
import com.atguigu.tingshu.vo.album.AlbumListVo;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.atguigu.tingshu.vo.search.AlbumInfoIndexVo;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

	@Autowired
	private AlbumInfoMapper albumInfoMapper;
    @Autowired
    private AlbumAttributeValueMapper albumAttributeValueMapper;
    @Autowired
    private AlbumStatMapper albumStatMapper;
    @Autowired
    private TrackInfoMapper trackInfoMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    @Lazy  //等使用时在从容器中装配
    AlbumInfoService albumInfoService;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveAlbumInfo(AlbumInfoVo albumInfoVo) {
        //1、保存专辑数据
        AlbumInfo albumInfo = new AlbumInfo();
        BeanUtils.copyProperties(albumInfoVo , albumInfo);//属性拷贝
        //设置前端没有提交的 需要后端设置的属性值
        //1.1 设置用户id
        albumInfo.setUserId(AuthContextHolder.getUserId());//目前还未实现登录
        //1.2 专辑中包含声音的数量
        albumInfo.setIncludeTrackCount(0);
        //TODO 1.3 是否完结：需要根据属性值判断
        albumInfo.setIsFinished(0); //默认未完结
        List<AlbumAttributeValueVo> attributeValueVos = albumInfoVo.getAlbumAttributeValueVoList();
        if(!CollectionUtils.isEmpty(attributeValueVos) ){
            //获取 标签属性 是否完结的属性
//            SystemConstant
            attributeValueVos.forEach(attributeValueVo->{
                //已完结
                if(attributeValueVo.getValueId().equals(SystemConstant.ALBUM_IS_FINISH)){
                    albumInfo.setIsFinished(1);
                }
            });
        }

        //1.4 免费试听的级数： 需要根据收费状态判断
        //tracksForFree    //0103
        // 如果专辑不是免费的 设置前五集免费试听
        if(!albumInfo.getPayType().equals(SystemConstant.ALBUM_PAY_TYPE_FREE)){
            albumInfo.setTracksForFree(5);
            //前30秒免费
            albumInfo.setSecondsForFree(30);
        }
        //1.5 专辑的状态: 默认设置为审核通过()
        albumInfo.setStatus(SystemConstant.TRACK_STATUS_PASS);

        albumInfoMapper.insert(albumInfo);
        //2、保存专辑的标签属性和值
        attributeValueVos.forEach(albumAttributeValueVo -> {
            AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
            BeanUtils.copyProperties(albumAttributeValueVo ,albumAttributeValue );
            //绑定专辑id  // 专辑标签属性 需要使用专辑id关联
            albumAttributeValue.setAlbumId(albumInfo.getId());
            albumAttributeValueMapper.insert(albumAttributeValue);
        });

        //3、初始化专辑的统计数据
//        SystemConstant

        //播放量
        saveAlbumStat(albumInfo.getId() , SystemConstant.ALBUM_STAT_PLAY);
        saveAlbumStat(albumInfo.getId() , SystemConstant.ALBUM_STAT_SUBSCRIBE);//订阅
        saveAlbumStat(albumInfo.getId() , SystemConstant.ALBUM_STAT_BROWSE);//浏览
        saveAlbumStat(albumInfo.getId() , SystemConstant.ALBUM_STAT_COMMENT);//评论


        //判断 如果专辑不是私密的，发送mq消息 ， search服务 将新增专辑数据导入到es中
        // 发送mq消息：只发送专辑id
        if(albumInfo.getIsOpen().equals("1")){
            rabbitTemplate.convertAndSend(
                    RabbitConstant.ALBUM_EXCHANGE , RabbitConstant.ALBUM_UPPER_RK,
                    albumInfo.getId()   );
        }


    }


    private void saveAlbumStat(Long albumId,String albumStatType) {
        AlbumStat albumStat = new AlbumStat();
        albumStat.setAlbumId(albumId);
        albumStat.setStatType(albumStatType);//统计类型
        albumStat.setStatNum(0);
        albumStatMapper.insert(albumStat);
    }

    //查询专辑分页数据的业务
    @Override
    public Page<AlbumListVo> findUserAlbumPage(Long pageNum, Long pageSize, AlbumInfoQuery albumInfoQuery) {
        //自定义sql实现查询
        //将用户id获取设置到参数中
        albumInfoQuery.setUserId(AuthContextHolder.getUserId());
        // mybatisplus 只需要将 page对象传入+ 配置了分页拦截器 它会自动拼接分页sql
        return albumInfoMapper.selectUserAlbumPage(new Page<AlbumListVo>(pageNum,pageSize),albumInfoQuery);
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void removeAlbumInfoById(Long id) {
        //1、删除专辑： 只能删除没有声音的专辑
        //1.1 判断专辑是否有声音
        Long count = trackInfoMapper.selectCount(Wrappers.lambdaQuery(TrackInfo.class)
                .eq(TrackInfo::getAlbumId, id));
        if(count>0){
            //抛出异常后 全局异常处理器捕获 创建一个失败的Result对象响应
            throw new GuiguException(ResultCodeEnum.ALBUM_DELETE_ERROR);
        }
        //1.2 删除专辑
        albumInfoMapper.deleteById(id);
        //2、删除专辑的标签属性和值
        albumAttributeValueMapper.delete(Wrappers.lambdaQuery(AlbumAttributeValue.class)
                .eq(AlbumAttributeValue::getAlbumId , id));
        //3、删除专辑的统计数据
        albumStatMapper.delete(Wrappers.lambdaQuery(AlbumStat.class)
                .eq(AlbumStat::getAlbumId , id));


        rabbitTemplate.convertAndSend(
                RabbitConstant.ALBUM_EXCHANGE , RabbitConstant.ALBUM_DOWN_RK,
                id  );
    }

    @Override
    public AlbumInfo getAlbumInfo(Long id) {
        AlbumInfo albumInfo = albumInfoMapper.selectById(id);
        if(albumInfo!=null){
            //查询专辑的属性
            List<AlbumAttributeValue> albumAttributeValues = albumAttributeValueMapper.selectList(Wrappers.lambdaQuery(AlbumAttributeValue.class)
                    .eq(AlbumAttributeValue::getAlbumId, id));
            albumInfo.setAlbumAttributeValueVoList(albumAttributeValues);
        }

        return albumInfo;
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateAlbumInfo(Long id, AlbumInfoVo albumInfoVo) {
        //删除redis中当前专辑的缓存
        redisTemplate.delete("album:cache:["+id+"]");
        //1、更新专辑信息
        AlbumInfo albumInfo = new AlbumInfo();
        BeanUtils.copyProperties(albumInfoVo , albumInfo);
        albumInfo.setId(id);
        albumInfoMapper.updateById(albumInfo);
        //2、更新标签 属性和值
        //2.1 先删除本专辑的所有的标签属性和值
        albumAttributeValueMapper.delete(Wrappers.lambdaQuery(AlbumAttributeValue.class)
                .eq(AlbumAttributeValue::getAlbumId , id));
        //2.2 再将本次提交的专辑的标签属性和值 保存
        albumInfoVo.getAlbumAttributeValueVoList().forEach(albumAttributeValueVo -> {
            AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
            BeanUtils.copyProperties(albumAttributeValueVo ,albumAttributeValue );
            //绑定专辑id  // 专辑标签属性 需要使用专辑id关联
            albumAttributeValue.setAlbumId(albumInfo.getId());
            albumAttributeValueMapper.insert(albumAttributeValue);
        });
        //将更新后的专辑数据 同步到es中
        // 只要更新，专辑的状态是开放的，就整个文档覆盖更新
        //判断 如果专辑不是私密的，发送mq消息 ， search服务 将新增专辑数据导入到es中
        // 发送mq消息：只发送专辑id
        if(albumInfo.getIsOpen().equals("1")){
            rabbitTemplate.convertAndSend(
                    RabbitConstant.ALBUM_EXCHANGE , RabbitConstant.ALBUM_UPPER_RK,
                    albumInfo.getId()   );
        }else{
            rabbitTemplate.convertAndSend(
                    RabbitConstant.ALBUM_EXCHANGE , RabbitConstant.ALBUM_DOWN_RK,
                    albumInfo.getId()   );
        }
        //延迟删除 该专辑的缓存数据
        // Async: springTask异步框架
//        ThreadPoolConfig.getExecutor()
//                .execute(()->{
//                    try {
//                        Thread.sleep(3000);
//                        redisTemplate.delete("album:cache:["+id+"]");
//                    } catch (InterruptedException e) {
//                        throw new RuntimeException(e);
//                    }
//                });
        //@Async原理：动态代理！！
        // 同一个组件类中，方法内互相调用时 隐式使用this调用
        //   会导致调用的方法上加的注解动态代理会失效
        // 解决： 调用每一个方法时都需要从容器中获取代理对象调用
        albumInfoService.deleteCacheAsync("album:cache:["+id+"]");
        this.deleteCacheAsync("album:cache:["+id+"]");
        System.out.println("111111111111111111");
    }
    //spring 自动异步执行，我们可以为他配置异步任务的线程池
    @Async  //springboot需要启用异步框架
    public void deleteCacheAsync(String cacheKey){
        try {
            Thread.sleep(3000);
            redisTemplate.delete(cacheKey);
            System.out.println("22222222222222222222222");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
    @Override
    public Page<AlbumListVo> getAlbumInfoIndexVoPage(Long pageNum, Long pageSize) {
        Page<AlbumListVo> albumPage = albumInfoMapper.selectUserAlbumPage(new Page<>(pageNum, pageSize), new AlbumInfoQuery());
        return albumPage;
    }

    @Override
    public List<AttributeValueIndex> findAttributesByAlbumId(Long albumId) {
        return albumAttributeValueMapper.selectList(Wrappers.lambdaQuery(AlbumAttributeValue.class)
                .eq(AlbumAttributeValue::getAlbumId , albumId)).stream()
                .map(albumAttributeValue -> {
                    AttributeValueIndex index = new AttributeValueIndex();
                    BeanUtils.copyProperties(albumAttributeValue,index);
                    return index;
                }).collect(Collectors.toList());
    }

    @Override
    public AlbumListVo getAlbumListVo(Long id) {
        return albumInfoMapper.selectAlbumListVo(id);
    }

    @Override
    public AlbumStatVo getAlbumStatVo(Long id) {

        return albumStatMapper.selectAlbumStatVo(id);
    }
}
